import axios from "axios";

import type {
  AxiosInstance,
  AxiosError,
  AxiosResponse,
  AxiosRequestConfig,
} from "axios";

export interface Result<T = any> {
  code?: number;
  data: T;
  message?: string;
}

export const useHttp = async <T>(axiosConfig: AxiosRequestConfig) => {
  const config = useRuntimeConfig();
  const apiBaseUrl = config.public.apiBaseUrl;

  const axiosInstance: AxiosInstance = axios.create({ baseURL: apiBaseUrl });

  axiosInstance.interceptors.request.use(
    function (config) {
      return config;
    },
    function (error) {
      return Promise.reject(error);
    },
  );

  axiosInstance.interceptors.response.use(
    function (response: AxiosResponse) {
      return response;
    },
    function (error: AxiosError) {
      return Promise.reject(error);
    },
  );

  class HttpRequest {
    static async request<T = any>(config: AxiosRequestConfig): Promise<T> {
      try {
        const res = await axiosInstance(config);
        const { data, message } = res.data as Result<T>;
        if (data !== undefined) {
          return data;
        } else {
          throw new Error("net error");
        }
      } catch (e) {
        throw new Error(JSON.stringify(e));
      }
    }

    static get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
      return this.request({ ...config, url, method: "get" });
    }

    static post<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
      return this.request({ ...config, url, method: "post" });
    }

    static put<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
      return this.request({ ...config, url, method: "put" });
    }

    static delete<T = any>(
      url: string,
      config?: AxiosRequestConfig,
    ): Promise<T> {
      return this.request({ ...config, url, method: "delete" });
    }

    static head<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
      return this.request({ ...config, url, method: "head" });
    }

    static patch<T = any>(
      url: string,
      config?: AxiosRequestConfig,
    ): Promise<T> {
      return this.request({ ...config, url, method: "patch" });
    }
  }

  return HttpRequest.request<T>(axiosConfig);
};
